using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Drawing.Design;
using System.Collections.Specialized;

namespace rach
{
    [Docking(DockingBehavior.AutoDock)]
    [DefaultEvent("DataClick")]

    public partial class ucData : UserControl
    {
        private List<ucDataFilter> m_FilterList = new List<ucDataFilter>();

        public ucData()
        {
            InitializeComponent();

            this.dgvData.AutoGenerateColumns = true;
            this.scData.Panel2Collapsed = true;
        }

        // ***

        /*public Label Label
        {
            get { return this.lblTitle; }
            //set { this.lblTitle = value; }
        }*/

        private bool m_LabelVisible = true;
        [DefaultValue(true)]
        public bool LabelVisible
        {
            get { return this.m_LabelVisible; }
            set
            {
                this.m_LabelVisible = value;
                this.lblTitle.Visible = value;
            }
        }

        private string m_LabelText = "";
        [DefaultValue("")]
        public string LabelText
        {
            get { return this.m_LabelText; }
            set
            {
                this.m_LabelText = value;
                this.lblTitle.Text = value;
            }
        }

        // ***

        public BindingNavigator BindingNavigator
        {
            get { return this.bnData; }
            //set { this.bnData = value; }
        }

        private bool m_FilterVisible = true;
        [DefaultValue(true)]
        public bool FilterVisible
        {
            get { return this.m_FilterVisible; }
            set
            {
                this.m_FilterVisible = value;
                this.bnDataFilterItem.Visible = value;
                this.bnDataSeparator3.Visible = value;
                if (value)
                {
                    FillColumnList(this.m_FilterColumns);
                }
                else
                {
                    this.m_FilterColumns.Clear();
                }
            }
        }

        private StringCollection m_FilterColumns = new StringCollection();
        [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
        public StringCollection FilterColumns
        {
            get { return this.m_FilterColumns; }
            set { this.m_FilterColumns = value; }
        }

        //***

        public DataGridView DataGridView
        {
            get { return this.dgvData; }
            //set { this.dgvData = value; }
        }

        [Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [DefaultValue("")]
        public string DataMember
        {
            get { return this.dgvData.DataMember; }
            set { this.dgvData.DataMember = value; }
        }

        [RefreshProperties(RefreshProperties.Repaint)]
        [DefaultValue("")]
        [AttributeProvider(typeof(IListSource))]
        public object DataSource
        {
            get { return this.dgvData.DataSource; }
            set { this.dgvData.DataSource = value; }
        }

        private BindingSource BindingSource
        {
            get
            {
                if (!(this.dgvData.DataSource is BindingSource)) return null;

                return (BindingSource)this.dgvData.DataSource;
            }
        }

        [RefreshProperties(RefreshProperties.Repaint)]
        [DefaultValue("")]
        public string DataSort
        {
            get
            {
                BindingSource bs = this.BindingSource;
                if (bs == null) return "";

                return bs.Sort;
            }
            set
            {
                BindingSource bs = this.BindingSource;
                if (bs == null) return;
                bs.Sort = value;
            }
        }

        private void SetVisibleColumns()
        {
            foreach (DataGridViewColumn dgvc in this.dgvData.Columns)
            {
                dgvc.Visible = (this.m_DataColumnsAll || this.m_DataColumns.Contains(dgvc.DataPropertyName));
            }
        }

        private StringCollection m_DataColumns = new StringCollection();
        [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
        public StringCollection DataColumns
        {
            get { return this.m_DataColumns; }
            set
            {
                this.m_DataColumns = value;
                SetVisibleColumns();
            }
        }

        private bool m_DataColumnsAll = true;
        [DefaultValue(true)]
        public bool DataColumnsAll
        {
            get { return this.m_DataColumnsAll; }
            set
            {
                this.m_DataColumnsAll = value;
                if (value)
                {
                    FillColumnList(this.m_DataColumns);
                }
                SetVisibleColumns();
            }
        }

        public DataRowView DataCurrent
        {
            get
            {
                BindingSource bs = this.BindingSource;
                if (bs == null) return null;

                return (DataRowView)bs.Current;
            }
        }

        public static void SetBSPosition(BindingSource bs, int value)
        {
            if (bs == null) return;
            if (value < 0) return;

            try
            {
                PropertyDescriptorCollection pdc = bs.CurrencyManager.GetItemProperties();

                int pos = bs.Find(pdc["ID"], value);

                if (pos >= 0) bs.Position = pos;
            }
            catch
            {
            }
        }

        [DefaultValue(-1)]
        public int DataID
        {
            get
            {
                DataRowView drv = this.DataCurrent;
                if (drv == null) return -1;
                else
                {
                    return (int)drv.Row.ItemArray[0];
                }
            }
            set
            {
                /*if (value < 0) return;

                BindingSource bs = this.BindingSource;
                if (bs == null) return;*/

                SetBSPosition(this.BindingSource, value);
                /*try
                {
                    PropertyDescriptorCollection pdc = bs.CurrencyManager.GetItemProperties();

                    int pos = bs.Find(pdc["ID"], value);

                    if (pos >= 0) bs.Position = pos;
                }
                catch
                {
                }*/
            }
        }

        private void SetColumnsSize()
        {
            foreach (DataGridViewColumn dgvc in this.dgvData.Columns)
            {
                dgvc.AutoSizeMode = this.m_DataColumnsSize.Contains(dgvc.DataPropertyName) ? DataGridViewAutoSizeColumnMode.AllCells : DataGridViewAutoSizeColumnMode.Fill;
            }
        }

        private StringCollection m_DataColumnsSize = new StringCollection();
        [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
        public StringCollection DataColumnsSize
        {
            get { return this.m_DataColumnsSize; }
            set
            {
                this.m_DataColumnsSize = value;
                SetColumnsSize();
            }
        }

        private StringCollection m_DataColumnsReadOnly = new StringCollection();
        [Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))]
        public StringCollection DataColumnsReadOnly
        {
            get { return this.m_DataColumnsReadOnly; }
            set
            {
                this.m_DataColumnsReadOnly = value;
            }
        }

        /*public DataGridViewColumnCollection DataColumns
        {
            get { return this.dgvData.Columns; }
            //set { this.dgvData.Columns = value; }
        }*/

        //*

        public class DataCellEventArgs : DataGridViewCellEventArgs
        {
            public DataRowView RowView = null;

            public DataCellEventArgs(DataRowView row, DataGridViewCellEventArgs e)
                : base(e.ColumnIndex, e.RowIndex)
            {
                this.RowView = row;
            }

            public DataCellEventArgs(DataGridView dgv, DataGridViewCellEventArgs e)
                : base(e.ColumnIndex, e.RowIndex)
            {
                DataGridViewRow dgvr = dgv.Rows[e.RowIndex];
                this.RowView = (DataRowView)dgvr.DataBoundItem;
            }
        }

        public class DataCellFormattingEventArgs : DataGridViewCellFormattingEventArgs
        {
            public DataRowView RowView = null;

            public DataCellFormattingEventArgs(DataGridView dgv, DataGridViewCellFormattingEventArgs e)
                : base(e.ColumnIndex, e.RowIndex, e.Value, e.DesiredType, e.CellStyle)
            {
                DataGridViewRow dgvr = dgv.Rows[e.RowIndex];
                this.RowView = (DataRowView)dgvr.DataBoundItem;
            }
        }

        public class DataCellCancelEventArgs : DataGridViewCellCancelEventArgs
        {
            public DataRowView RowView = null;
            private DataGridViewCellCancelEventArgs m_e = null;

            public DataCellCancelEventArgs(DataGridView dgv, DataGridViewCellCancelEventArgs e)
                : base(e.ColumnIndex, e.RowIndex)
            {
                this.m_e = e;

                DataGridViewRow dgvr = dgv.Rows[e.RowIndex];
                this.RowView = (DataRowView)dgvr.DataBoundItem;
            }

            new public bool Cancel
            {
                get { return base.Cancel; }
                set
                {
                    base.Cancel = value;
                    this.m_e.Cancel = value;
                }
            }
        }

        public class DataCellParsingEventArgs : DataGridViewCellParsingEventArgs
        {
            public DataRowView RowView = null;
            private DataGridViewCellParsingEventArgs m_e = null;

            public DataCellParsingEventArgs(DataGridView dgv, DataGridViewCellParsingEventArgs e)
                : base(e.RowIndex, e.ColumnIndex, e.Value, e.DesiredType, e.InheritedCellStyle)
            {
                this.m_e = e;

                DataGridViewRow dgvr = dgv.Rows[e.RowIndex];
                this.RowView = (DataRowView)dgvr.DataBoundItem;
            }

            new public bool ParsingApplied
            {
                get { return base.ParsingApplied; }
                set
                {
                    base.ParsingApplied = value;
                    this.m_e.ParsingApplied = value;
                }
            }

            new public object Value
            {
                get { return base.Value; }
                set
                {
                    base.Value = value;
                    this.m_e.Value = value;
                }
            }
        }

        public delegate void DataCellEventHandler(object sender, DataCellEventArgs e);
        public delegate void DataCellFormattingEventHandler(object sender, DataCellFormattingEventArgs e);
        public delegate void DataCellCancelEventHandler(object sender, DataCellCancelEventArgs e);
        public delegate void DataCellParsingEventHandler(object sender, DataCellParsingEventArgs e);

        public event DataCellEventHandler DataCellClick;
        public event DataCellEventHandler DataCellDblClick;
        public event DataCellEventHandler DataCellValueChanged;
        public event DataCellEventHandler DataRowEnter;
        public event DataCellFormattingEventHandler DataCellFormatting;
        public event DataCellCancelEventHandler DataCellBeginEdit;
        public event DataCellParsingEventHandler DataCellParsing;

        //public event DataGridViewColumnEventHandler DataColumnAdded;

        //**

        private void FillColumnList()
        {
            FillColumnList(this.m_DataColumns, this.m_FilterColumns);
        }

        private void FillColumnList(params StringCollection[] strings)
        {
            foreach (StringCollection sc in strings)
            {
                sc.Clear();
            }

            foreach (DataGridViewColumn dgvc in this.dgvData.Columns)
            {
                foreach (StringCollection sc in strings)
                {
                    sc.Add(dgvc.DataPropertyName);
                }
            }
        }

        private void dgvData_DataSourceChanged(object sender, EventArgs e)
        {
            BindingSource bs = this.BindingSource;
            if (bs == null) return;

            bs.RemoveFilter();
            this.bnData.BindingSource = bs;
            if (this.LabelText == null || this.LabelText.Length == 0)
                this.LabelText = bs.DataMember;

            if (this.FilterVisible && this.DataColumnsAll)
            {
                FillColumnList();
            }
            else if (this.DataColumnsAll)
            {
                FillColumnList(this.m_DataColumns, this.m_DataColumnsSize);
            }
            
            if (this.DesignMode)
            {
                if (this.m_DataColumnsSize.Count == 0)
                {
                    FillColumnList(this.m_DataColumnsSize);
                }
                if (this.m_DataColumnsReadOnly.Count == 0)
                {
                    FillColumnList(this.m_DataColumnsReadOnly);
                }
            }
        }

        private void bnData_RefreshItems(object sender, EventArgs e)
        {
            this.bnDataFilterItem.Enabled = (this.bnDataPositionItem.Enabled || this.FilterVisible);
        }

        private void bnDataFilterItem_CheckedChanged(object sender, EventArgs e)
        {
            this.scData.Panel2Collapsed = !this.bnDataFilterItem.Checked;

            BindingSource bs = this.BindingSource;

            this.m_FilterList.Clear();
            foreach (string s in this.m_FilterColumns)
            {
                PropertyDescriptorCollection pdc = bs.CurrencyManager.GetItemProperties();
                PropertyDescriptor pd = pdc[s];

                this.m_FilterList.Add(new ucDataFilter(pd.PropertyType, s));
            }

            this.ucDataFilterBindingSource.DataSource = this.m_FilterList;

            //if (bs == null) return;
            bs.RemoveFilter();
        }

        private void dgvFilter_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            e.Cancel = (e.ColumnIndex == 0);
        }

        private void dgvData_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
        {
            e.Column.Visible = (this.DataColumnsAll || this.m_DataColumns.Contains(e.Column.DataPropertyName));
            e.Column.AutoSizeMode = this.m_DataColumnsSize.Contains(e.Column.DataPropertyName) ? DataGridViewAutoSizeColumnMode.AllCells : DataGridViewAutoSizeColumnMode.Fill;
            e.Column.ReadOnly = e.Column.ReadOnly ? true : this.m_DataColumnsReadOnly.Contains(e.Column.DataPropertyName);

            /*if (this.DataColumnAdded == null) return;

            this.DataColumnAdded(sender, e);*/
        }

        private void FilterData()
        {
            BindingSource bs = this.BindingSource;
            if (bs == null) return;

            string s = "";
            foreach (ucDataFilter df in this.m_FilterList)
            {
                if (df.Value == null) continue;

                s = (s.Length > 0) ? s + " and " + df.GetFilter() : df.GetFilter();
            }
            bs.Filter = s;
        }

        private void dgvFilter_KeyUp(object sender, KeyEventArgs e)
        {
            FilterData();
        }

        private void dgvData_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (this.DataCellClick == null) return;
            if (this.DataCurrent == null) return;

            this.DataCellClick(this, new DataCellEventArgs(this.DataCurrent, e));
        }

        private void dgvData_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (this.DataCellDblClick == null) return;
            if (this.DataCurrent == null) return;

            this.DataCellDblClick(this, new DataCellEventArgs(this.DataCurrent, e));
        }

        private void dgvData_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (this.DataCellValueChanged == null) return;

            this.DataCellValueChanged(this, new DataCellEventArgs(this.dgvData, e));
        }

        private void dgvData_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (this.DataCellFormatting == null) return;

            this.DataCellFormatting(this, new DataCellFormattingEventArgs(this.dgvData, e));
        }

        private void dgvData_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (this.DataRowEnter == null) return;

            this.DataRowEnter(this, new DataCellEventArgs(this.dgvData, e));
        }

        private void dgvData_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (this.DataCellBeginEdit == null) return;

            this.DataCellBeginEdit(this, new DataCellCancelEventArgs(this.dgvData, e));
        }

        private void dgvData_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
        {
            if (this.DataCellParsing == null) return;

            this.DataCellParsing(this, new DataCellParsingEventArgs(this.dgvData, e));
        }

        private void tsmCopyItem_Click(object sender, EventArgs e)
        {
            if (this.DataCurrent == null) return;
            
            DataRow row = this.DataCurrent.Row;

            object o = row[this.dgvData.CurrentCell.ColumnIndex];
            Clipboard.SetText(o.ToString());
        }

        private void dgvData_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (e.RowIndex < 0) return;

                this.dgvData.CurrentCell = this.dgvData[e.ColumnIndex, e.RowIndex];
            }
        }

        private void tsmCopyRowItem_Click(object sender, EventArgs e)
        {
            if (this.DataCurrent == null) return;

            Clipboard.SetDataObject(this.dgvData.GetClipboardContent());
        }
    }

    public class ucDataFilter
    {
        private Type m_Type;
        private string m_Field = null;
        private object m_Value = null;

        public ucDataFilter(Type type, string field)
        {
            this.m_Type = type;
            this.m_Field = field;
        }

        public ucDataFilter(string field, object value)
        {
            this.m_Type = value.GetType();
            this.m_Field = field;
            this.m_Value = value;
        }

        public string Field
        {
            get { return this.m_Field; }
            set { this.m_Field = value; }
        }

        public object Value
        {
            get { return this.m_Value; }
            set { this.m_Value = value; }
        }

        private string GetNullFilter()
        {
            return string.Format("{0} is {1}", this.m_Field, this.m_Value);
        }

        private string GetLikeFilter()
        {
            return string.Format("{0} like '*{1}*'", this.m_Field, this.m_Value.ToString());
        }

        private string GetEqualFilter()
        {
            return string.Format("{0} = {1}", this.m_Field, this.m_Value);
        }

        public string GetFilter()
        {
            return this.m_Value.ToString().ToLower().Contains("null") ? GetNullFilter() :
                ((this.m_Type.Name.ToLower().Contains("int") ||
                this.m_Type.Name.ToLower().Contains("bool")) ? GetEqualFilter() : GetLikeFilter());
        }
    }

}
